/**
 * Copyright (C) 2009+ Spark Zheng
 *
 * @file        src/buffer.c 
 * @date        2010-04-05
 * @brief	may block.
 * @see         dlib
 * @history
 */

#include <string.h>
#include <stdlib.h>
#include "buffer.h"
#include "mempool.h"

dlib_buffer_t *dlib_buffer_init(size_t size)
{
	dlib_buffer_t *buffer = NULL;
	if (size == 0) {
		return NULL;
	}
	buffer = dmalloc_nb(sizeof(*buffer) + size);
	if (buffer == NULL) {
		return NULL;
	}
	buffer->buff_size = size;
	buffer->buff_offset = 0;
	return buffer;
}

dlib_buffer_t *dlib_buffer_set_offset(dlib_buffer_t *buffer, size_t offset)
{
	if (buffer == NULL) {
		return NULL;
	}
	if (offset > buffer->buff_size) {
		buffer->buff_offset = buffer->buff_size;
	} else {
		buffer->buff_offset = offset;
	}
	*(buffer->buffer + buffer->buff_offset) = 0;
	return buffer;
}

dlib_buffer_t *dlib_buffer_append(dlib_buffer_t *buffer, const char *append, size_t len)
{
	if (buffer == NULL || append == NULL || len == 0) {
		return NULL; 
	}

	if (buffer->buff_size - buffer->buff_offset < len + 1) {
		size_t expand  = buffer->buff_size > len ? buffer->buff_size : len;
		dlib_buffer_t *temp = NULL;
		temp = drealloc_nb(buffer, sizeof(*buffer) + buffer->buff_size + expand);
		if (temp != NULL) {
			buffer = temp;
			buffer->buff_size += expand;
		} else {
			return NULL;
		}
	} 

	memcpy(buffer->buffer + buffer->buff_offset, append, len);
	buffer->buff_offset += len;
	*(buffer->buffer + buffer->buff_offset) = 0;

	return buffer;
}

dlib_buffer_t *dlib_buffer_prepend(dlib_buffer_t *buffer, const char *prepend, size_t len)
{
	buffer = dlib_buffer_append(buffer, prepend, len);
	if (buffer == NULL) {
		return NULL;
	}

	char temp;

	/* double reverse */
	size_t i = 0;
	size_t j = buffer->buff_offset - 1;
	for (; i < j; i++, j--) {
		temp = buffer->buffer[j];
		buffer->buffer[j] = buffer->buffer[i];
		buffer->buffer[i] = temp;
	}
	
	i = 0;
	j = len - 1;
	for (; i < j; i++, j--) {
		temp = buffer->buffer[j];
		buffer->buffer[j] = buffer->buffer[i];
		buffer->buffer[i] = temp;
	}

	i = len;
	j = buffer->buff_offset - 1;
	for (; i < j; i++, j--) {
		temp = buffer->buffer[j];
		buffer->buffer[j] = buffer->buffer[i];
		buffer->buffer[i] = temp;
	}

	return buffer;
}

void dlib_buffer_exit(dlib_buffer_t *buffer)
{
	if (buffer != NULL) {
		dfree(buffer);
		buffer = NULL;
	}
	return;
}

void dlib_buffer_dump(dlib_buffer_t *buffer, FILE *fp)
{
	if (fp == NULL)
		fp = stdout;

	fprintf(fp, "BUFFER dump out:\n"
		"    buffer:               %p\n"
		"    buffer->buff_size:    %u\n"
		"    buffer->buff_offset:  %u\n"
		"    buffer->buffer:       %s\n",
		buffer, buffer->buff_size, buffer->buff_offset,
		buffer->buffer);
	
	return;
}
